#ifndef __SDS_H
#define __SDS_H

#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>

typedef char* sds;

struct __attribute__ ((__packed__)) sdshdr5 {
	unsigned char flags;  /* 3lsb of type, and 5 msb of string length  */
	char buf[];
};

struct __attribute__ ((__packed__)) sdshdr8 {
	uint8_t len;
	uint8_t alloc;
	unsigned char flags;
	char buf[];
};

struct __attribute__ ((__packed__)) sdshdr16 {
	uint16_t len;
	uint16_t alloc;
	unsigned char flags;
	char buf[];
};


#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2

#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3


#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s) - sizeof(struct sdshdr##T));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s) - (sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)

static inline size_t sdslen(const sds s) {
	unsigned char flags = s[-1];
	switch(flags & SDS_TYPE_MASK){
	case SDS_TYPE_5:
		return SDS_TYPE_5_LEN(flags);
	case SDS_TYPE_8:
		return SDS_HDR(8,s)->len;
	case SDS_TYPE_16:
		return SDS_HDR(16,s)->len;
	}
	return 0;
}

sds sdsnewlen(const void *init, size_t initlen);
sds sdsnew(const char *init);
sds sdsempty();
void sdsfree(sds s);


#endif /* __SDS_H  */

